﻿#region Using References

using System.Collections.Generic;
using Beaker.OpenCube.Specs.Builders;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NUnit.Framework;

#endregion

namespace Beaker.OpenCube.Specs
{
	[TestClass]
	public class ObservableExpandObjectSpecs
	{
		[TestMethod]
		public void UpdatingHardcodedPropertyShouldReturnSameValueOnGet()
		{
			// arrange
			ObservableExpandoTestObject expandoObject = new ObservableExpandoObjectBuilder()
				.Build();

			// act
			expandoObject.Hard = "Foobar";

			// assert
			expandoObject.Hard.Should().Be( "Foobar" );
		}

		[TestMethod]
		public void UpdatingSoftcodedPropertyShouldReturnSameValueOnGet()
		{
			// arrange
			ObservableExpandoTestObject expandoObject = new ObservableExpandoObjectBuilder()
				.Build();

			// act
			expandoObject.Soft = "Foobar";

			// assert
			expandoObject.Soft.Should().Be( "Foobar" );
		}

		#region Dynamic

		[TestMethod]
		public void UpdatingDynamicPropertyShouldReturnSameValueOnGet()
		{
			// arrange
			dynamic expandoObject = new ObservableExpandoObjectBuilder()
				.Build();

			// act
			expandoObject.Dynamic = "Foobar";

			// assert
			( (string)expandoObject.Dynamic ).Should().Be( "Foobar" );
		}

		[TestMethod]
		public void UpdatingDynamicPropertyShouldResultInKeyAvailable()
		{
			// arrange
			ObservableExpandoTestObject expandoObject = new ObservableExpandoObjectBuilder()
				.Build();

			// act
			( (dynamic)expandoObject ).Dynamic = "Foobar";

			// assert
			expandoObject.ExpandoProperties.ContainsKey("Dynamic").Should().Be( true );
		}

		[TestMethod]
		public void SequenceReturnedByGetAllExpandoPropertiesShouldReturnAllTheExpandoProperties()
		{
			// arrange
			dynamic expandoObject = new ObservableExpandoObjectBuilder()
				.Build();

			expandoObject.Me = "Me";
			expandoObject.Five = 5;
			expandoObject.Negative = -2.657d;

			// act
			IReadOnlyDictionary<string, object> properties = ( (ObservableExpandoObject)expandoObject ).ExpandoProperties;

			// assert
			properties.Should().Contain(
				new[]
				{
					new KeyValuePair<string, object>( "Me", "Me" ),
					new KeyValuePair<string, object>( "Five", 5 ),
					new KeyValuePair<string, object>( "Negative", -2.657d ),
				}
			);
		}

		[TestMethod]
		public void SequenceReturnedByGetAllExpandoPropertyNamesShouldReturnAllTheExpandoPropertyNames()
		{
			// arrange
			dynamic expandoObject = new ObservableExpandoObjectBuilder()
				.Build();

			expandoObject.Me = "Me";
			expandoObject.Five = 5;
			expandoObject.Negative = -2.657d;

			// act
			IEnumerable<string> properties = ( (ObservableExpandoObject)expandoObject ).ExpandoProperties.Keys;

			// assert
			properties.Should().Contain(
				new[] { "Me", "Five", "Negative" }
			);
		}

		[TestMethod]
		public void UpdatingDynamicPropertyShouldRaisePropertyChangedEvent()
		{

			// arrange
			bool hasRaised = false;
			string raisedPropertyName = null;
			ObservableExpandoTestObject expandoObject = new ObservableExpandoObjectBuilder()
				.Build();

			expandoObject.PropertyChanged += ( s, ea ) =>
			{
				raisedPropertyName = ea.PropertyName;
				hasRaised = true;
			};

			// act
			( (dynamic)expandoObject ).Dynamic = "Foobar";

			// assert
			hasRaised.Should().Be( true );
			raisedPropertyName.Should().Be( "Dynamic" );
		}

		[TestMethod]
		public void UpdatingDynamicPropertyShouldRaisePropertyChangingEvent()
		{

			// arrange
			bool hasRaised = false;
			string raisedPropertyName = null;
			ObservableExpandoTestObject expandoObject = new ObservableExpandoObjectBuilder()
				.Build();

			expandoObject.PropertyChanging += ( s, ea ) =>
			{
				raisedPropertyName = ea.PropertyName;
				hasRaised = true;
			};

			// act
			( (dynamic)expandoObject ).Dynamic = "Foobar";

			// assert
			hasRaised.Should().Be( true );
			raisedPropertyName.Should().Be( "Dynamic" );
		}

		#endregion
	}
}